package com.psedu.base.service.impl;

import com.psedu.base.domain.Apply;
import com.psedu.base.domain.vo.MergeDeptInfo;
import com.psedu.base.domain.vo.SemesterDeptVo;
import com.psedu.base.mapper.ApplyMapper;
import com.psedu.base.mapper.SemesterDeptMapper;
import com.psedu.base.service.MergeClassService;
import com.psedu.base.service.SeatService;
import com.psedu.base.utils.POIUtils;
import com.psedu.base.utils.PSPOIUtils;
import com.psedu.common.core.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class SeatServiceImpl implements SeatService {

    @Autowired
    private ApplyMapper applyMapper;

    @Autowired
    private SemesterDeptMapper semesterDeptMapper;

    @Autowired
    private MergeClassService mergeClassService;

    /**
     * 为所有合班分配座位，生成Excel
     * @param semeId 学期ID
     */
    @Override
    public HSSFWorkbook assignMergeClassSeat(Long semeId) {

        MergeDeptInfo mergeDeptInfo = mergeClassService.getMergeDeptInfo(semeId);
        List<List<SemesterDeptVo>> mergeClassList = mergeDeptInfo.getMergeClassList();

        // 将部门信息填入Map<deptId, deptName>
        HashMap<Long, String> deptNameMap = getDeptNameMap(mergeClassList);
        HSSFWorkbook workbook = getWorkbook();
        int mergeClassNum = mergeClassList.size();
        POIUtils.cloneSheet(workbook, mergeClassNum -1);
        for(int i = 0; i < mergeClassNum; i++) {
            workbook.setSheetName(i, "第" +(i +1) +"合班座位表");
        }
        validSeatEnough(mergeClassList, workbook);
        // 填入培训名称
        for(int nowMergeClassId = 1; nowMergeClassId <= mergeClassNum; nowMergeClassId++) {
            HSSFSheet nowSheet = workbook.getSheetAt(nowMergeClassId - 1);
            PSPOIUtils.fillTitle(workbook, nowSheet, mergeDeptInfo.getTrainName());
        }
        // 循环为分班填充座位
        for(int nowMergeClassId = 1; nowMergeClassId <= mergeClassNum; nowMergeClassId++) {
            List<SemesterDeptVo> nowSemesterDeptVos = mergeClassList.get(nowMergeClassId - 1);
            HSSFSheet nowSheet = workbook.getSheetAt(nowMergeClassId -1);
            // 当前分班包含的部门
            List<Long> nowMergeClassDeptIds = nowSemesterDeptVos
                    .stream()
                    .map(SemesterDeptVo::getDeptId)
                    .collect(Collectors.toList());
            // 将学员分配进座位
            List<Apply> waitAssignStudentList = applyMapper.selectMergeClassStudent(semeId, nowMergeClassId);
            log.info("等待分配学员：" +waitAssignStudentList.size());
            List<Apply> assignedApplyList = new ArrayList<>();
            Map<Long, HSSFCellStyle> seatStyleMap = new HashMap<>();
            // 规定每个学院的 cell style 进入map
            getGroupCellStyle2Map(workbook, seatStyleMap, nowMergeClassDeptIds);
            int lastRowNum = nowSheet.getLastRowNum();
            int nowStudentCount = 0;
            // 遍历Excel格子，填充学员进入座位，更改学员位置
            for (int h = 0; h <= lastRowNum; h++) {
                HSSFRow row = nowSheet.getRow(h);
                for (int l = 0; row != null && l <= row.getLastCellNum(); l++) {
                    HSSFCell cell = row.getCell(l);
                    // 不是空位
                    if (!PSPOIUtils.isEmptySeatCell(cell)) {
                        continue;
                    }
                    // 宽度
                    nowSheet.setColumnWidth((short) l, 3000);
                    // 分配座位，填充颜色
                    if (waitAssignStudentList.size() != 0) {
                        Apply apply = waitAssignStudentList.get(0);
                        waitAssignStudentList.remove(0);
                        // TOOD merge
                        cell.setCellValue(apply.getRealName());
                        HSSFCellStyle cellStyle = seatStyleMap.get(apply.getDeptId());
                        cell.setCellStyle(cellStyle);
                        // 学员座位
                        apply.setSeatNum((long) (nowMergeClassId * 1000 + nowStudentCount));
                        assignedApplyList.add(apply);
                        nowStudentCount++;
                        // 清除空位标志
                    } else {
                        cell.setCellValue("");
                    }
                }
            }
            // 座位同步到数据库
            applyMapper.updateBatchById(assignedApplyList);
            log.info("已经分配座位学员：" +assignedApplyList.size());
            fillGroupStyleCell(deptNameMap, nowSheet, nowMergeClassDeptIds, seatStyleMap);
        }
        return workbook;
    }

    private HSSFWorkbook getWorkbook() {
        HSSFWorkbook workbook = POIUtils.loadHSSFWorkbookByResourcePath(PSPOIUtils.SEAT_RESOURCES_PATH);
        if(workbook == null) {
            log.error("未找到位置Excel文件:{}", PSPOIUtils.SEAT_RESOURCES_PATH);
            throw new ServiceException("未找到位置Excel文件");
        }
        return workbook;
    }

    private HashMap<Long, String> getDeptNameMap(List<List<SemesterDeptVo>> mergeClassList) {
        HashMap<Long, String> deptNameMap = new HashMap<>();
        for (List<SemesterDeptVo> semesterDeptVos : mergeClassList) {
            for (SemesterDeptVo semesterDeptVo : semesterDeptVos) {
                deptNameMap.put(semesterDeptVo.getDeptId(), semesterDeptVo.getDeptName());
            }
        }
        return deptNameMap;
    }

    /**
     * 合班位置足够
     * @param mergeClassList 合班学员数量List
     * @param workbook 座位
     */
    private void validSeatEnough(List<List<SemesterDeptVo>> mergeClassList, HSSFWorkbook workbook) {
        // 获取各分班人数
        List<Integer> mergeClassStudentNumList = new ArrayList<>();
        // 获取每个合班的人数
        for (List<SemesterDeptVo> semesterDeptVos : mergeClassList) {
            int studentNum = 0;
            // 每个学院
            for (SemesterDeptVo semesterDeptVo : semesterDeptVos) {
                studentNum += semesterDeptVo.getStudentNum();
            }
            // 填充合班人数
            mergeClassStudentNumList.add(studentNum);
        }
        // 计算位置
        int seatCount = PSPOIUtils.getSheetSeatCount(workbook.getSheetAt(0));
        for(int nowMergeClassId = 1; nowMergeClassId <= mergeClassStudentNumList.size(); nowMergeClassId++) {
            Integer studentCount = mergeClassStudentNumList.get(nowMergeClassId - 1);
            // 位置太少
            if (seatCount < studentCount) {
                throw new ServiceException("学员过多，位置坐不下，学员数量：" + studentCount + "，座位数量" + seatCount);
            }
        }
    }


    @Override
    public void downloadMergeClassSeat(HttpServletResponse response, Long semeId) {
        HSSFWorkbook hssfWorkbook = assignMergeClassSeat(semeId);
        outExcelStream(response, hssfWorkbook, "党校培训座位表");
    }



    /**
     * 填充分组（分党校）颜色信息
     * @param deptMap 部门ID： 部门名称
     * @param sheet excel
     * @param deptIds 部门List
     * @param seatStyleMap 座位styleMap 部门：Cell分割
     */
    private void fillGroupStyleCell(HashMap<Long, String> deptMap,
                                    HSSFSheet sheet,
                                    List<Long> deptIds,
                                    Map<Long, HSSFCellStyle> seatStyleMap) {
        int lastRowNum = sheet.getLastRowNum();
        // 座位颜色信息，0：颜色，1：属于的分党校
        int contentType = 0;
        int index = 0;
        // 将颜色信息填入
        for (int h = 0; h <= lastRowNum; h++) {
            HSSFRow row = sheet.getRow(h);
            for (int l = 0; row != null && l <= row.getLastCellNum(); l++) {
                HSSFCell cell = row.getCell(l);
                // 不是空位
                if (!PSPOIUtils.isStyleInfoCell(cell)) {
                    continue;
                }
                // 填入
                if(index < deptIds.size() *2) {
                    // 颜色
                    if(contentType == 0) {
                        HSSFCellStyle cellStyle = seatStyleMap.get(
                                deptIds.get(index /2)
                        );
                        cell.setCellStyle(cellStyle);
                        contentType = 1;
                    // 颜色信息
                    } else {
                        cell.setCellValue(
                                deptMap.get(
                                        deptIds.get(index /2)
                                )
                        );

                        contentType = 0;
                    }
                    index++;
                // 填满了
                } else {
                    cell.setCellValue("");
                }
            }
        }
    }

    /**
     * 规定每个学院的 cell style 进入map
     * @param workbook workbook
     * @param seatStyleMap 格子的风格
     * @param groupIdList groupIdList
     */
    private void getGroupCellStyle2Map(HSSFWorkbook workbook, Map<Long, HSSFCellStyle> seatStyleMap, List<Long> groupIdList) {
        for (int i = 0; i < groupIdList.size(); i++) {
            Long groupId = groupIdList.get(i);
            HSSFCellStyle cellStyle = workbook.createCellStyle();
            // 垂直居中
            cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
            // 上下居中
            cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
            // 边框
            cellStyle.setBorderBottom(HSSFCellStyle.BORDER_MEDIUM);
            cellStyle.setBorderLeft(HSSFCellStyle.BORDER_MEDIUM);
            cellStyle.setBorderTop(HSSFCellStyle.BORDER_MEDIUM);
            cellStyle.setBorderRight(HSSFCellStyle.BORDER_MEDIUM);
            // 背景
            cellStyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
            cellStyle.setFillForegroundColor( PSPOIUtils.COLOR_LIST.get(i) );
            seatStyleMap.put(groupId, cellStyle);
        }
    }

    /**
     * 通过流的方式输出excle到页面
     * @param response 响应
     * @param workbook 工作空间
     * @param fileName 文件名
     */
    @Override
    public void outExcelStream(HttpServletResponse response, Workbook workbook, String fileName){
        OutputStream os = null;
        try {
            os = response.getOutputStream();
            response.setContentType("application/x-download");
            response.setCharacterEncoding("UTF-8");
            response.setHeader("Content-disposition", "attachment;filename=" + new String(fileName.getBytes(), "ISO8859-1") + ".xls");
            workbook.write(os);
            os.flush();
        }catch (Exception e) {
            e.printStackTrace();
        }finally {
            if(os!=null){
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
